﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ProgNetComponents.Design.Attributes;
using System.ComponentModel;

namespace ProgNetComponents.Validation.Rules
{
    /// <summary>
    /// Numeric value validation rule
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class ColumnNumericValueValidationRule<T> : ColumnValidationRule where T:IComparable
    {
        #region Static
        /// <summary>
        /// Initializes the <see cref="ColumnNumericValueValidationRule{T}"/> class.
        /// </summary>
        static ColumnNumericValueValidationRule()
        {
            GlobalDefaultErrorStringEqual = "Ta wartość powinna być równa {0}.";
            GlobalDefaultErrorStringNotEqual = "Ta wartość powinna być różna od {0}.";
            GlobalDefaultErrorStringBigger = "Ta wartość powinna być większa od {0}.";
            GlobalDefaultErrorStringBiggerOrEqual = "Ta wartość powinna być większa lub równa {0}.";
            GlobalDefaultErrorStringLess = "Ta wartość powinna być mniejsza od {0}.";
            GlobalDefaultErrorStringLessOrEqual = "Ta wartość powinna być mniejsza lub równa {0}.";
            GlobalDefaultErrorStringInRange = "Ta wartość powinna być z zakresu {0} do {1}.";
            GlobalDefaultErrorStringNotInRange = "Ta wartość powinna być z poza zakresu {0} do {1}.";
        }

        /// <summary>
        /// Gets or sets the global default error string equal.
        /// </summary>
        /// <value>
        /// The global default error string equal.
        /// </value>
        public static string GlobalDefaultErrorStringEqual { get; set; }
        /// <summary>
        /// Gets or sets the global default error string not equal.
        /// </summary>
        /// <value>
        /// The global default error string not equal.
        /// </value>
        public static string GlobalDefaultErrorStringNotEqual { get; set; }
        /// <summary>
        /// Gets or sets the global default error string bigger.
        /// </summary>
        /// <value>
        /// The global default error string bigger.
        /// </value>
        public static string GlobalDefaultErrorStringBigger { get; set; }
        /// <summary>
        /// Gets or sets the global default error string bigger or equal.
        /// </summary>
        /// <value>
        /// The global default error string bigger or equal.
        /// </value>
        public static string GlobalDefaultErrorStringBiggerOrEqual { get; set; }
        /// <summary>
        /// Gets or sets the global default error string less.
        /// </summary>
        /// <value>
        /// The global default error string less.
        /// </value>
        public static string GlobalDefaultErrorStringLess { get; set; }
        /// <summary>
        /// Gets or sets the global default error string less or equal.
        /// </summary>
        /// <value>
        /// The global default error string less or equal.
        /// </value>
        public static string GlobalDefaultErrorStringLessOrEqual { get; set; }
        /// <summary>
        /// Gets or sets the global default error string in range.
        /// </summary>
        /// <value>
        /// The global default error string in range.
        /// </value>
        public static string GlobalDefaultErrorStringInRange { get; set; }
        /// <summary>
        /// Gets or sets the global default error string not in range.
        /// </summary>
        /// <value>
        /// The global default error string not in range.
        /// </value>
        public static string GlobalDefaultErrorStringNotInRange { get; set; }

        #endregion

        /// <summary>
        /// Gets the default error string.
        /// </summary>
        /// <value>
        /// The default error string.
        /// </value>
        protected override string DefaultErrorString
        {
            get
            {
                switch (Comparsion)
                {
                    case NumberComparcion.Equal:
                        return GlobalDefaultErrorStringEqual;
                    case NumberComparcion.NotEqual:
                        return GlobalDefaultErrorStringNotEqual;
                    case NumberComparcion.Bigger:
                        return GlobalDefaultErrorStringBigger;
                    case NumberComparcion.BiggerOrEqual:
                        return GlobalDefaultErrorStringBiggerOrEqual;
                    case NumberComparcion.Less:
                        return GlobalDefaultErrorStringLess;
                    case NumberComparcion.LessOrEqual:
                        return GlobalDefaultErrorStringLessOrEqual;
                    case NumberComparcion.InRange:
                        return GlobalDefaultErrorStringInRange;
                    case NumberComparcion.NotInRange:
                        return GlobalDefaultErrorStringNotInRange;
                    default:
                        return null;
                }
            }
        }

        /// <summary>
        /// Gets formatted error string
        /// </summary>
        /// <value>
        /// The formated error string.
        /// </value>
        public override string FormatedErrorString
        {
            get { return ErrorString.XFormat(Value, MaxValue); }
        }
        /// <summary>
        /// Gets or sets the comparsion.
        /// </summary>
        /// <value>
        /// The comparsion.
        /// </value>
        [RefreshProperties(System.ComponentModel.RefreshProperties.All)]
        public NumberComparcion Comparsion
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the value.
        /// </summary>
        /// <value>
        /// The value.
        /// </value>
        public T Value
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the maximum value.
        /// </summary>
        /// <value>
        /// The maximum value.
        /// </value>
        [BrowsableByPropertyValue("Comparsion", NumberComparcion.InRange, NumberComparcion.NotInRange)]
        public T MaxValue
        {
            get;
            set;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ColumnNumericValueValidationRule{T}"/> class.
        /// </summary>
        protected ColumnNumericValueValidationRule()
            : base()
        {
           
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="ColumnNumericValueValidationRule{T}"/> class.
        /// </summary>
        /// <param name="column">The column.</param>
        /// <param name="value">The value.</param>
        /// <param name="comparsion">The comparsion.</param>
        /// <param name="error">The error.</param>
        protected ColumnNumericValueValidationRule(string column, T value, NumberComparcion comparsion, string error):base(column,error)
        {
             Value = value;
             Comparsion = comparsion;
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="ColumnNumericValueValidationRule{T}"/> class.
        /// </summary>
        /// <param name="column">The column.</param>
        /// <param name="value">The value.</param>
        /// <param name="max">The maximum.</param>
        /// <param name="comparsion">The comparsion.</param>
        /// <param name="error">The error.</param>
        protected ColumnNumericValueValidationRule(string column, T value, T max, NumberComparcion comparsion, string error)
            : base(column, error)
        {
            Value = value;
            MaxValue = max;
            Comparsion = comparsion;
        }

        /// <summary>
        /// Does the validate.
        /// </summary>
        /// <param name="row">The row.</param>
        /// <returns></returns>
        protected override bool DoValidate(System.Data.DataRow row)
        {
            T val = ConvertValue(row[Column]);
            switch (Comparsion)
            {
                case NumberComparcion.Equal:
                    return val.CompareTo(Value) == 0;
                case NumberComparcion.NotEqual:
                    return val.CompareTo(Value) != 0;
                case NumberComparcion.Bigger:
                    return val.CompareTo(Value) >0;
                case NumberComparcion.BiggerOrEqual:
                    return val.CompareTo(Value) >= 0;
                case NumberComparcion.Less:
                    return val.CompareTo(Value) < 0;
                case NumberComparcion.LessOrEqual:
                    return val.CompareTo(Value) <= 0;
                case NumberComparcion.InRange:
                    return val.CompareTo(Value) >= 0 && val.CompareTo(MaxValue) <=0;
                case NumberComparcion.NotInRange:
                    return val.CompareTo(Value) < 0 || val.CompareTo(MaxValue) > 0;
                default:
                    return true;
            }
        }

        /// <summary>
        /// Converts the value.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        protected abstract T ConvertValue(object value);
    }

    /// <summary>
    /// Int value validation rule
    /// </summary>
    public class ColumnIntValueValidationRule : ColumnNumericValueValidationRule<int>
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="ColumnIntValueValidationRule"/> class.
        /// </summary>
        public ColumnIntValueValidationRule()
        {

        }
        /// <summary>
        /// Initializes a new instance of the <see cref="ColumnIntValueValidationRule"/> class.
        /// </summary>
        /// <param name="column">The column.</param>
        /// <param name="value">The value.</param>
        /// <param name="comparsion">The comparsion.</param>
        /// <param name="error">The error.</param>
        protected ColumnIntValueValidationRule(string column, int value, NumberComparcion comparsion, string error):base(column, value, comparsion, error)
        {
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="ColumnIntValueValidationRule"/> class.
        /// </summary>
        /// <param name="column">The column.</param>
        /// <param name="value">The value.</param>
        /// <param name="max">The maximum.</param>
        /// <param name="comparsion">The comparsion.</param>
        /// <param name="error">The error.</param>
        protected ColumnIntValueValidationRule(string column, int value, int max, NumberComparcion comparsion, string error)
            : base(column, value, max, comparsion, error)
        {
           
        }

        /// <summary>
        /// Converts the value.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        protected override int ConvertValue(object value)
        {
            return value.AsInt();
        }
    }

    /// <summary>
    /// Decimal value validation rule
    /// </summary>
    public class ColumnDecimalValueValidationRule : ColumnNumericValueValidationRule<decimal>
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="ColumnDecimalValueValidationRule"/> class.
        /// </summary>
        public ColumnDecimalValueValidationRule()
        {

        }
        /// <summary>
        /// Initializes a new instance of the <see cref="ColumnDecimalValueValidationRule"/> class.
        /// </summary>
        /// <param name="column">The column.</param>
        /// <param name="value">The value.</param>
        /// <param name="comparsion">The comparsion.</param>
        /// <param name="error">The error.</param>
        protected ColumnDecimalValueValidationRule(string column, decimal value, NumberComparcion comparsion, string error)
            : base(column, value, comparsion, error)
        {
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="ColumnDecimalValueValidationRule"/> class.
        /// </summary>
        /// <param name="column">The column.</param>
        /// <param name="value">The value.</param>
        /// <param name="max">The maximum.</param>
        /// <param name="comparsion">The comparsion.</param>
        /// <param name="error">The error.</param>
        protected ColumnDecimalValueValidationRule(string column, decimal value, decimal max, NumberComparcion comparsion, string error)
            : base(column, value, max, comparsion, error)
        {

        }

        /// <summary>
        /// Converts the value.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        protected override decimal ConvertValue(object value)
        {
            return value.AsDecimal();
        }
    }
}
